import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import com.google.common.collect.Multimap;

public class Client {
	private static JPanel contentPane;
	private static MyMenuBar menuBar;
	private static TabbedPopupMenu tabbedPopupMenu;
	private static QueryContentPopupMenu queryContentPopupMenu;
	private static MyToolBar toolBar;
	private static JTabbedPane contentTabbedPane;
	private static JFileChooser saveChooser;
	private static JFileChooser openChooser;
	private static ObjectInputStream ois;
	private static ObjectOutputStream oos;
	private static JFrame login;
	private static Vector database;

	public static void createAndShowGUI() {
		try {
			UIManager
					.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}

		openChooser = new JFileChooser();
		openChooser.setFileFilter(new QueryFilter());
		openChooser.setAcceptAllFileFilterUsed(false);
		saveChooser = new JFileChooser();
		saveChooser.setFileFilter(new QueryFilter());
		saveChooser.setAcceptAllFileFilterUsed(false);

		JFrame frame = new JFrame("Client");
		// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent we) {
				try {
					oos.writeObject("!!!quit!!!");
					oos.flush();
					oos.close();
					ois.close();
				} catch (Exception ex) {
					System.out.println("Server đã đóng!");
				}
				login.setVisible(true);
			}
		});

		menuBar = new MyMenuBar();
		frame.setJMenuBar(menuBar);

		tabbedPopupMenu = new TabbedPopupMenu();
		queryContentPopupMenu = new QueryContentPopupMenu();

		contentPane = (JPanel) frame.getContentPane();
		contentPane.setLayout(new BorderLayout());

		contentTabbedPane = new JTabbedPane();

		toolBar = new MyToolBar(database);
		contentPane.add(toolBar, BorderLayout.PAGE_START);
		contentPane.add(contentTabbedPane, BorderLayout.CENTER);

		frame.setSize(new Dimension(900, 600));
		frame.setExtendedState(Frame.MAXIMIZED_BOTH);
		frame.setVisible(true);
	}

	public static void createNewQuery() {
		QueryTab.number++;
		QueryTab splitPane = new QueryTab(queryContentPopupMenu, "");
		contentTabbedPane.addTab("Query " + QueryTab.number, splitPane);
		contentTabbedPane.setSelectedComponent(splitPane);
		contentTabbedPane.setComponentPopupMenu(tabbedPopupMenu);
	}

	public static void openQuery(String path, String tabName) {
		JSplitPane splitPane = new QueryTab(queryContentPopupMenu, path);
		contentTabbedPane.addTab(tabName, splitPane);
		contentTabbedPane.setSelectedComponent(splitPane);
		contentTabbedPane.setComponentPopupMenu(tabbedPopupMenu);
	}

	public static void showResultPanel() {
		QueryTab queryTab = (QueryTab) (contentTabbedPane
				.getSelectedComponent());
		queryTab.setDividerLocation(0.3);
		JPanel resultPanel = queryTab.resultPanel;
		resultPanel.setVisible(true);
	}

	public static int getNumberTable(Vector result) {
		int kq = 0;
		for (int i = 0; i < result.size(); i++) {
			if (result.elementAt(i) instanceof Map) {
				String error = getError((Map)result.elementAt(i));
				if (error == null) {
					kq++;
				}
			}
		}
		return kq;
	}

	public static JSplitPane createMultiSplitPane(int nTab, int totalSize) {
		if (nTab == 0) {
			return null;
		}
		int height = totalSize/nTab;
		JSplitPane result = new JSplitPane();
		result.setOrientation(JSplitPane.VERTICAL_SPLIT);
		if (nTab == 1) {
			result.setDividerSize(0);
			result.setDividerLocation(height);
			result.setResizeWeight(0.5);
			result.setRightComponent(null);
		} else if (nTab >= 2) {
			JSplitPane temp = result;
			temp.setDividerLocation(height);
			temp.setResizeWeight(0.5);
			for (int i = 0; i < nTab - 2; i++) {
				JSplitPane sp = new JSplitPane();
				temp.setRightComponent(sp);
				sp.setDividerLocation(height);
				sp.setResizeWeight(0.5);
				sp.setOrientation(JSplitPane.VERTICAL_SPLIT);
				temp = sp;
			}
		}
		return result;
	}
	
	public static void showResultTable(JSplitPane sp, Map hm, int position,
			int nTab) {
		if (nTab == 0) {
			return;
		}
		QueryTab queryTab = (QueryTab) (contentTabbedPane
				.getSelectedComponent());
		JTable table = new JTable(new MyTableModel(hm));
		table.setFillsViewportHeight(false);
		table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		table.setCellSelectionEnabled(true);
		table.getColumnModel().getColumn(0).setPreferredWidth(30);
		JScrollPane js = new JScrollPane(table);
		JSplitPane temp = sp;
		if (position < nTab) {

			for (int i = 0; i < position - 1; i++) {
				temp = (JSplitPane) temp.getRightComponent();
			}
			temp.setLeftComponent(js);
		} else if (position == nTab) {
			if (nTab == 1) {
				temp.setLeftComponent(js);
			} else {
				for (int i = 0; i < position - 2; i++) {
					temp = (JSplitPane) temp.getRightComponent();
				}
				temp.setRightComponent(js);
			}
		}
	}

	public static void showResult(Map hm) {
		QueryTab queryTab = (QueryTab) (contentTabbedPane
				.getSelectedComponent());

		JPanel resultPanel = queryTab.resultPanel;
		if (resultPanel.isVisible() == false) {
			queryTab.setDividerLocation(0.5);
			resultPanel.setVisible(true);
		}
		JTable table = new JTable(new MyTableModel(hm));
		table.setFillsViewportHeight(false);
		table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		table.setCellSelectionEnabled(true);
		table.getColumnModel().getColumn(0).setPreferredWidth(30);
		JScrollPane js = new JScrollPane(table);

		JPanel resultTab = queryTab.resultTab;
		if (resultTab.getComponentCount() > 0) {
			resultTab.removeAll();
		}
		resultTab.add(js, BorderLayout.CENTER);
		resultTab.updateUI();
	}

	public static class ItemListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			String str = e.getActionCommand();
			if (str.equals("toolbar_newquery")) {
				createNewQuery();
			} else if (str.equals("toolbar_execute")
					|| str.equals("executequery")) {
				if (contentTabbedPane.getComponentCount() > 0) {
					if (contentTabbedPane.getSelectedComponent() instanceof QueryTab) {
						QueryTab queryTab = (QueryTab) contentTabbedPane
								.getSelectedComponent();
						try {
							if (queryTab.queryContentArea.getSelectedText() == null) {
								oos.writeObject(queryTab.queryContentArea
										.getText());
							} else {
								oos.writeObject(queryTab.queryContentArea
										.getSelectedText());
							}
							oos.writeObject(toolBar.selectDB.getSelectedItem()
									.toString());

							// Xử lý kết quả trả về
							queryTab.messageAreaTab.setText("");
							JPanel resultTab = queryTab.resultTab;
							resultTab.removeAll();
							resultTab.updateUI();
							Vector returnVal = (Vector) ois.readObject();
							if (queryTab.resultPanel.isVisible() == false
									&& queryTab.queryContentArea.getText()
											.compareToIgnoreCase("") != 0) {
								showResultPanel();
							}
							int nTab = getNumberTable(returnVal);		
							JSplitPane sp = createMultiSplitPane(nTab, queryTab.getHeight() - queryTab.getDividerLocation() - 45);
							if (sp != null) {
								resultTab.add(sp);
							}
							int numError = 0;
							int position = 0;
							for (int i = 0; i < returnVal.size(); i++) {
								if (returnVal.elementAt(i) instanceof Map) {
									Map result = (Map) returnVal.elementAt(i);
									String error = getError(result);
									if (error == null) {
										position++;
										showResultTable(sp, result, position, nTab);
									} else {
										numError++;
										appendMessage(queryTab.messageAreaTab,
												error);
									}
								} else if (returnVal.elementAt(i) instanceof Integer) {
									int code = (int) returnVal.elementAt(i);
									System.out.println(code);
									if (code > 0) {
										appendMessage(queryTab.messageAreaTab,
												code + " row(s) affected");
									} else {
										switch (code) {
										case -10:
											appendMessage(
													queryTab.messageAreaTab,
													Anncouncement.ERROR_SYNTAX
															.getDescription());
											break;
										case -11:
											appendMessage(
													queryTab.messageAreaTab,
													Anncouncement.ERROR_TABLE_EXIST
															.getDescription());
											break;
										case -12:
											appendMessage(
													queryTab.messageAreaTab,
													Anncouncement.ERROR_FIELD_EXIST
															.getDescription());
											break;
										case -21:
											appendMessage(
													queryTab.messageAreaTab,
													Anncouncement.ERROR_INSERT_FEWER
															.getDescription());
											break;
										case -22:
											appendMessage(
													queryTab.messageAreaTab,
													Anncouncement.ERROR_INSERT_MORE
															.getDescription());
											break;
										case -23:
											appendMessage(
													queryTab.messageAreaTab,
													Anncouncement.ERROR_INSERT_PRIMARYKEYDUB
															.getDescription());
											break;
										case -13:
											appendMessage(
													queryTab.messageAreaTab,
													Anncouncement.ERROR_CONVERT_TO_INT
															.getDescription());
											break;
										}
										numError++;
									}
								}
							}
							if(numError >0) {
								queryTab.notice.setForeground(Color.red);
								queryTab.notice.setText("Query completed with errors!");
							} else {
								queryTab.notice.setForeground(Color.black);
								queryTab.notice.setText("Query executed successfully!");
							}
							resultTab.updateUI();

							/*
							 * for (int i = 0; i < returnVal.size(); i++) { if
							 * (returnVal.elementAt(i) instanceof Map) { Map
							 * result = (Map) returnVal.elementAt(i); String
							 * error = getError(result); if (error == null) {
							 * showResult(result); } else {
							 * appendMessage(queryTab.messageAreaTab, error); }
							 * } else if (returnVal.elementAt(i) instanceof
							 * Integer) { int code = (int)
							 * returnVal.elementAt(i); if (code > 0) {
							 * appendMessage(queryTab.messageAreaTab, code +
							 * " row(s) affected"); } else { switch (code) {
							 * case -10: appendMessage( queryTab.messageAreaTab,
							 * Anncouncement.ERROR_SYNTAX .getDescription());
							 * break; case -11: appendMessage(
							 * queryTab.messageAreaTab,
							 * Anncouncement.ERROR_TABLE_EXIST
							 * .getDescription()); break; case -12:
							 * appendMessage( queryTab.messageAreaTab,
							 * Anncouncement.ERROR_FIELD_EXIST
							 * .getDescription()); break; case -21:
							 * appendMessage( queryTab.messageAreaTab,
							 * Anncouncement.ERROR_INSERT_FEWER
							 * .getDescription()); break; case -22:
							 * appendMessage( queryTab.messageAreaTab,
							 * Anncouncement.ERROR_INSERT_MORE
							 * .getDescription()); break; case -23:
							 * appendMessage( queryTab.messageAreaTab,
							 * Anncouncement.ERROR_INSERT_PRIMARYKEYDUB
							 * .getDescription()); break; case -13:
							 * appendMessage( queryTab.messageAreaTab,
							 * Anncouncement.ERROR_CONVERT_TO_INT
							 * .getDescription()); break; } } } }
							 */
							// Map result = (Map) ois.readObject();
							// showResult(result);
						} catch (Exception ex) {
							ex.printStackTrace();
						}
					}
				}
			} else if (str.equals("toolbar_open")) {
				int returnVal = openChooser.showOpenDialog(null);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					String path = openChooser.getSelectedFile()
							.getAbsolutePath();
					String name = openChooser.getSelectedFile().getName();
					openQuery(path, name);
				}
			} else if (str.equals("savetab") || str.equals("toolbar_save")) {
				if (contentTabbedPane.getSelectedComponent() instanceof QueryTab) {
					QueryTab queryTab = (QueryTab) (contentTabbedPane
							.getSelectedComponent());
					if (queryTab.location == "") {
						String fildName = contentTabbedPane
								.getTitleAt(contentTabbedPane
										.getSelectedIndex());
						saveChooser.setSelectedFile(new File(fildName));
						int returnVal = saveChooser.showSaveDialog(null);
						if (returnVal == JFileChooser.APPROVE_OPTION) {
							String path = saveChooser.getSelectedFile()
									.getAbsolutePath();
							String name = saveChooser.getSelectedFile()
									.getName();
							if (!(path.endsWith(".query"))) {
								path += ".query";
								name += ".query";
							}
							queryTab.location = path;
							try {
								FileOutputStream fout = new FileOutputStream(
										new File(path));
								BufferedWriter bw = new BufferedWriter(
										new OutputStreamWriter(fout, "UTF-16"));
								bw.append(queryTab.queryContentArea.getText());
								bw.close();
								fout.close();
							} catch (Exception ex) {
							}
							contentTabbedPane.setTitleAt(
									contentTabbedPane.getSelectedIndex(), name);
						}
					} else {
						try {
							FileOutputStream fout = new FileOutputStream(
									new File(queryTab.location));
							BufferedWriter bw = new BufferedWriter(
									new OutputStreamWriter(fout, "UTF-16"));
							bw.append(queryTab.queryContentArea.getText());
							bw.close();
							fout.close();
						} catch (Exception ex) {
						}
					}
				}
			} else if (str.equals("cutquery")) {
				QueryTab queryTab = (QueryTab) (contentTabbedPane
						.getSelectedComponent());
				queryTab.queryContentArea.cut();
			} else if (str.equals("copyquery")) {
				QueryTab queryTab = (QueryTab) (contentTabbedPane
						.getSelectedComponent());
				queryTab.queryContentArea.copy();
			} else if (str.equals("pastequery")) {
				QueryTab queryTab = (QueryTab) (contentTabbedPane
						.getSelectedComponent());
				queryTab.queryContentArea.paste();
			} else if (str.equals("closetab")) {
				contentTabbedPane.remove(contentTabbedPane
						.getSelectedComponent());
			} else if (str.equals("closeallbutthistab")) {
				for (int i = contentTabbedPane.getTabCount() - 1; i >= 0; i--) {
					if (i != contentTabbedPane.getSelectedIndex()) {
						contentTabbedPane.remove(contentTabbedPane
								.getComponentAt(i));
					}
				}
			} else if (str.equals("closealltab")) {
				for (int i = contentTabbedPane.getTabCount() - 1; i >= 0; i--) {
					contentTabbedPane.remove(contentTabbedPane
							.getComponentAt(i));
				}
			}
		}
	}

	public static void appendMessage(JTextArea messageArea, String message) {
		messageArea.append(message);
	}

	public static String getError(Map<String, Multimap<String, String>> m) {
		for (Map.Entry<String, Multimap<String, String>> e : m.entrySet()) {
			String key = e.getKey();
			Multimap<String, String> values = e.getValue();
			if (key.compareToIgnoreCase("error") == 0) {
				for (Entry<String, Collection<String>> entry : values.asMap()
						.entrySet()) {
					String att = (String) entry.getKey();
					List<String> value = new ArrayList<String>();
					value.addAll(entry.getValue());
					return value.get(0);
				}
			} else {
				return null;
			}
		}
		return null;
	}

	public static void runClient(JFrame lg, ObjectInputStream is,
			ObjectOutputStream os) {
		login = lg;
		ois = is;
		oos = os;
		try {
			database = (Vector) ois.readObject();
		} catch (Exception ex) {
		}
		createAndShowGUI();
	}
}
